﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using ArduinoInterOp.Abstract;

namespace ArduinoInterOp
{
    public enum SensorType
    {
        Input,
        Output,
    }

    public class ArduinoSetup : IEnumerable<KeyValuePair<byte, SensorType>>
    {
        private readonly Dictionary<byte, SensorType> _sensorTypeIndexBySensorPin;
        private readonly List<ArduinoCommand> _preloadedArduinoCommands;

        public ArduinoSetup()
        {
            _sensorTypeIndexBySensorPin = new Dictionary<byte, SensorType>();
            _preloadedArduinoCommands = new List<ArduinoCommand>();
        }

        public bool Valid
        {
            get { return true; }
        }

        internal string Communicate(IArduinoCommunication communication)
        {
            var setupCallback = communication.SendSyncedCommand(SetupString());

            if (!string.IsNullOrEmpty(setupCallback))
            {
                var setupFinish = communication.SendSyncedCommand("setupfinish");

                if (string.IsNullOrEmpty(setupFinish))
                {
                    // TODO:
                    throw new Exception();
                }

                return setupCallback;
            }
            else
            {
                // TODO:
                throw new Exception();
            }

        }

        private string SetupString()
        {
            var allStrings = new List<string>();

            foreach (var pinData in this)
            {
                int command = 0;
                command |= pinData.Key;
                command = command << 8;
                switch (pinData.Value)
                {
                    case SensorType.Input:
                        command += 1;
                        break;
                    case SensorType.Output:
                        break;
                    default:
                        throw new ArgumentOutOfRangeException();
                }

                allStrings.Add(command.ToString(CultureInfo.InvariantCulture));
            }

            return string.Join("|", allStrings) + "|";
        }

        public void AddPreloadedCommand(ArduinoCommand command)
        {
            _preloadedArduinoCommands.Add(command);
        }

        public string ValidErrorMessage { get; set; }

        public IEnumerable<ArduinoCommand> PreloadedArduinoCommands
        {
            get { return _preloadedArduinoCommands; }
        }

        public SensorType this[byte i]
        {
            get
            {
                if(this._sensorTypeIndexBySensorPin.ContainsKey(i))
                {
                    return this._sensorTypeIndexBySensorPin[i];
                }
                else
                {
                    //TODO: More informative
                    throw new IndexOutOfRangeException();
                }
            }
            set
            {
                if(!this._sensorTypeIndexBySensorPin.ContainsKey(i))
                {
                    this._sensorTypeIndexBySensorPin.Add(i, SensorType.Input);
                }

                this._sensorTypeIndexBySensorPin[i] = value;
            }
        }

        public IEnumerator<KeyValuePair<byte, SensorType>> GetEnumerator()
        {
            return this._sensorTypeIndexBySensorPin.GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return this._sensorTypeIndexBySensorPin.GetEnumerator();
        }
    }
}
